DearMiku

iOS安全 -- 越狱检测

字数统计: 984阅读时长: 4 min
2017/11/18 Share

iOS安全 – 越狱检测

越狱是什么

越狱是指利用iOS系统的默写漏洞,通过指令取得了iOS的root权限.可以自己优化系统,获得系统权限可以修改系统文件,可以安装更多拥有高系统权限的软件,实现更多高级功能!例如:与其他设备蓝牙发送文件、短信回执、来电归属地、文件管理、浏览器下载插件、flash插件、内容管理等等。

所以在越狱情况下,难免会有一些恶意应用会危害到我们的应用,所以我们需要检测当前是否为越狱环境,从而禁用或者关闭一些功能(如截获我们的网络请求/响应 进行修改,获取我们沙盒的文件,,,,).

越狱检测方法

检测沙盒机制和越狱工具

在越狱环境下,iOS的沙盒机制将被破坏,所以可以去访问本不能访问的路径.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (BOOL)checkPath
{
BOOL jailBroken = NO;
NSString * cydiaPath = @"/Applications/Cydia.app";
NSString * aptPath = @"/private/var/lib/apt";
if ([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
jailBroken = YES;
}
if ([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
jailBroken = YES;
}
return jailBroken;
}
·
上述路径也可替换为以下常见越狱工具路径:
/Library/MobileSubstrate/MobileSubstrate.dylib
/Applications/Cydia.app
/var/lib/cydia/
/var/cache/apt
/var/lib/apt
/etc/apt
/bin/bash
/bin/sh
/usr/sbin/sshd
/usr/libexec/ssh-keysign
/etc/ssh/sshd_config

因为有时NSFileManger函数会被hock掉,所以可以使用C语言stat函数进行路径检测

1
2
3
4
5
6
7
8
9
- (BOOL)checkCydia
{
struct stat stat_info;
//路径也可以进行替换
if (0 == stat("/Applications/Cydia.app", &stat_info)) {
return YES;
}
return NO;
}

程序运行环境变量检测

如果设置了 DYLD_INSERT_LIBRARIES 环境变量,那么在程序运行时,动态链接器会先加载该环境变量所指定的动态库;也就是说,这个动态库的加载优先于任何其它的库,包括 libc。

由于这个环境变量指定的动态库加载的时机实在是太早了,所以对于 app来说,除了代码混淆外,无良策;

但是我们可以在代码中通过判断环境变量来检测是不是被注入:

1
2
3
4
5
6
7
8
- (BOOL)checkEnv{
char *env = getenv("DYLD_INSERT_LIBRARIES");
NSLog(@"%s", env);
if (env) {
return YES;
}
return NO;
}

验证函数地址

使用dladdr方法可以获得一个函数所在的模块.从而判断该函数是否被替换掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <dlfcn.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdio.h>
#include <string.h>

Dl_info info;
IMP imp;
Method orginalMethod = class_getClassMethod([NSArray class], @selector(description));
imp = method_getImplementation(orginalMethod);
if (dladdr(imp, &info)) {
printf("dli_fname: %s\n", info.dli_fname);
printf("dli_sname: %s\n", info.dli_sname);
printf("dli_fbase: %p\n", info.dli_fbase);
printf("dli_saddr: %p\n", info.dli_saddr);
} else {
printf("error: can't find that symbol.\n");
}

通过该方法验证指定类的方法是否都来自指定模块(可以根据实际情况自定义修改),建议使用inline方式编译,像这样以内联函数的形式编译,攻击者必须修改每一处调用该函数的的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

#include <dlfcn.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdio.h>
#include <string.h>

static inline BOOL validate_methods(const char *cls,const char *fnamePre) __attribute__ ((always_inline));

BOOL validate_methods(const char *cls,const char *fnamePre){
Class aClass = objc_getClass(cls);
Method *methods;
unsigned int nMethods;
Dl_info info;
IMP imp;
Method m;
if(!aClass)
return NO;
methods = class_copyMethodList(aClass, &nMethods);
while (nMethods--) {
m = methods[nMethods];
imp = method_getImplementation(m);
if(!imp){
free(methods);
return NO;
}
if(!dladdr(imp, &info)){
free(methods);
return NO;
}
/*Validate image path*/
if(!strstr(info.dli_fname, fnamePre)){
goto FAIL;
}
}
return YES;

FAIL:
printf("method %s failed integrity test:\n",
(const char *)method_getName(m));
printf(" dli_fname:%s\n",info.dli_fname);
printf(" dli_sname:%s\n",info.dli_sname);
printf(" dli_fbase:%p\n",info.dli_fbase);
printf(" dli_saddr:%p\n",info.dli_saddr);
free(methods);
return NO;
}

最后,这种检查方式只能减少被攻击的可能性,不是肯定安全的,也是有可能被绕过的.

CATALOG
  1. 1. iOS安全 – 越狱检测
    1. 1.1. 越狱是什么
    2. 1.2. 越狱检测方法
      1. 1.2.1. 检测沙盒机制和越狱工具
      2. 1.2.2. 程序运行环境变量检测
      3. 1.2.3. 验证函数地址